#!/usr/bin/env ambari-python-wrap

# Python imports
import imp
import os
import traceback
import re
import socket
import fnmatch

from resource_management.core.logger import Logger

SCRIPT_DIR = os.path.dirname(os.path.abspath(__file__))
STACKS_DIR = os.path.join(SCRIPT_DIR, '../../../../')
PARENT_FILE = os.path.join(STACKS_DIR, 'service_advisor.py')

try:
    if "BASE_SERVICE_ADVISOR" in os.environ:
        PARENT_FILE = os.environ["BASE_SERVICE_ADVISOR"]
    with open(PARENT_FILE, 'rb') as fp:
        service_advisor = imp.load_module('service_advisor', fp, PARENT_FILE,
                                          ('.py', 'rb', imp.PY_SOURCE))
except Exception as e:
    traceback.print_exc()
    print "Failed to load parent"

DB_TYPE_DEFAULT_PORT_MAP = {
    "MYSQL": "3306",
    "ORACLE": "1521",
    "POSTGRES": "5432",
    "MSSQL": "1433",
    "SQLA": "2638"
}


class RangerServiceAdvisor(service_advisor.ServiceAdvisor):
    def __init__(self, *args, **kwargs):
        self.as_super = super(RangerServiceAdvisor, self)
        self.as_super.__init__(*args, **kwargs)

        # Always call these methods
        self.modifyMastersWithMultipleInstances()
        self.modifyCardinalitiesDict()
        self.modifyHeapSizeProperties()
        self.modifyNotValuableComponents()
        self.modifyComponentsNotPreferableOnServer()
        self.modifyComponentLayoutSchemes()

    def modifyMastersWithMultipleInstances(self):
        """
    Modify the set of masters with multiple instances.
    Must be overriden in child class.
    """
        # Nothing to do
        pass

    def modifyCardinalitiesDict(self):
        """
    Modify the dictionary of cardinalities.
    Must be overriden in child class.
    """
        # Nothing to do
        pass

    def modifyHeapSizeProperties(self):
        """
    Modify the dictionary of heap size properties.
    Must be overriden in child class.
    """
        pass

    def modifyNotValuableComponents(self):
        """
    Modify the set of components whose host assignment is based on other services.
    Must be overriden in child class.
    """
        # Nothing to do
        pass

    def modifyComponentsNotPreferableOnServer(self):
        """
    Modify the set of components that are not preferable on the server.
    Must be overriden in child class.
    """
        # Nothing to do
        pass

    def modifyComponentLayoutSchemes(self):
        """
    Modify layout scheme dictionaries for components.
    The scheme dictionary basically maps the number of hosts to
    host index where component should exist.
    Must be overriden in child class.
    """
        # Nothing to do
        pass

    def getServiceComponentLayoutValidations(self, services, hosts):
        """
    Get a list of errors.
    Must be overriden in child class.
    """

        return self.getServiceComponentCardinalityValidations(
            services, hosts, "RANGER")

    def getServiceConfigurationRecommendations(self, configurations,
                                               clusterData, services, hosts):
        """
    Entry point.
    Must be overriden in child class.
    """
        # Logger.info("Class: %s, Method: %s. Recommending Service Configurations." %
        #            (self.__class__.__name__, inspect.stack()[0][3]))

        recommender = RangerRecommender()
        recommender.recommendRangerConfigurationsFromHDP206(
            configurations, clusterData, services, hosts)
        recommender.recommendRangerConfigurationsFromHDP22(
            configurations, clusterData, services, hosts)
        recommender.recommendRangerConfigurationsFromHDP23(
            configurations, clusterData, services, hosts)
        recommender.recommendRangerConfigurationsFromHDP25(
            configurations, clusterData, services, hosts)
        recommender.recommendRangerConfigurationsFromHDP26(
            configurations, clusterData, services, hosts)
        recommender.recommendConfigurationsForSSO(configurations, clusterData,
                                                  services, hosts)
        recommender.recommendConfigurationsForHDP30(
            configurations, clusterData, services, hosts)
        recommender.recommendRangerConfigurationsFromHDP31(
            configurations, clusterData, services, hosts)

    def getServiceConfigurationRecommendationsForSSO(
            self, configurations, clusterData, services, hosts):
        """
    Entry point.
    Must be overriden in child class.
    """
        recommender = RangerRecommender()
        recommender.recommendConfigurationsForSSO(configurations, clusterData,
                                                  services, hosts)

    def getServiceConfigurationsValidationItems(
            self, configurations, recommendedDefaults, services, hosts):
        """
    Entry point.
    Validate configurations for the service. Return a list of errors.
    The code for this function should be the same for each Service Advisor.
    """
        # Logger.info("Class: %s, Method: %s. Validating Configurations." %
        #            (self.__class__.__name__, inspect.stack()[0][3]))

        validator = RangerValidator()
        # Calls the methods of the validator using arguments,
        # method(siteProperties, siteRecommendations, configurations, services, hosts)
        return validator.validateListOfConfigUsingMethod(
            configurations, recommendedDefaults, services, hosts,
            validator.validators)

    @staticmethod
    def isKerberosEnabled(services, configurations):
        """
    Determines if security is enabled by testing the value of core-site/hadoop.security.authentication enabled.
    If the property exists and is equal to "kerberos", then is it enabled; otherwise is it assumed to be
    disabled.

    :type services: dict
    :param services: the dictionary containing the existing configuration values
    :type configurations: dict
    :param configurations: the dictionary containing the updated configuration values
    :rtype: bool
    :return: True or False
    """
        if configurations and "core-site" in configurations and \
                "hadoop.security.authentication" in configurations["core-site"]["properties"]:
            return configurations["core-site"]["properties"][
                       "hadoop.security.authentication"].lower() == "kerberos"
        elif services and "core-site" in services["configurations"] and \
                "hadoop.security.authentication" in services["configurations"]["core-site"]["properties"]:
            return services["configurations"]["core-site"]["properties"][
                       "hadoop.security.authentication"].lower() == "kerberos"
        else:
            return False


class RangerRecommender(service_advisor.ServiceAdvisor):
    """
  Ranger Recommender suggests properties when adding the service for the first time or modifying configs via the UI.
  """

    def __init__(self, *args, **kwargs):
        self.as_super = super(RangerRecommender, self)
        self.as_super.__init__(*args, **kwargs)

    def recommendRangerConfigurationsFromHDP206(self, configurations,
                                                clusterData, services, hosts):

        putRangerAdminProperty = self.putProperty(configurations,
                                                  "admin-properties", services)

        # Build policymgr_external_url
        protocol = 'http'
        ranger_admin_host = 'localhost'
        port = '6080'

        # For Ranger-0.4.0 this can be checked in ranger-site/http.enabled
        if ('ranger-site' in services['configurations'] and 'http.enabled' in services['configurations']['ranger-site'][
            'properties'] \
            and services['configurations']['ranger-site']['properties']['http.enabled'].lower() == 'false') or \
                ('ranger-admin-site' in services['configurations'] and 'ranger.service.http.enabled' in
                 services['configurations']['ranger-admin-site']['properties'] \
                 and services['configurations']['ranger-admin-site']['properties'][
                     'ranger.service.http.enabled'].lower() == 'false'):
            # HTTPS protocol is used
            protocol = 'https'
            # Starting Ranger-0.5.0.2.3 port stored in ranger-admin-site ranger.service.https.port
            if 'ranger-admin-site' in services['configurations'] and \
                    'ranger.service.https.port' in services['configurations']['ranger-admin-site']['properties']:
                port = services['configurations']['ranger-admin-site'][
                    'properties']['ranger.service.https.port']
            # In Ranger-0.4.0 port stored in ranger-site https.service.port
            elif 'ranger-site' in services['configurations'] and \
                    'https.service.port' in services['configurations']['ranger-site']['properties']:
                port = services['configurations']['ranger-site']['properties'][
                    'https.service.port']
        else:
            # HTTP protocol is used
            # Starting Ranger-0.5.0.2.3 port stored in ranger-admin-site ranger.service.http.port
            if 'ranger-admin-site' in services['configurations'] and \
                    'ranger.service.http.port' in services['configurations']['ranger-admin-site']['properties']:
                port = services['configurations']['ranger-admin-site'][
                    'properties']['ranger.service.http.port']
            # In Ranger-0.4.0 port stored in ranger-site http.service.port
            elif 'ranger-site' in services['configurations'] and \
                    'http.service.port' in services['configurations']['ranger-site']['properties']:
                port = services['configurations']['ranger-site']['properties'][
                    'http.service.port']

        ranger_admin_hosts = self.getComponentHostNames(
            services, "RANGER", "RANGER_ADMIN")
        if ranger_admin_hosts:
            if len(ranger_admin_hosts) > 1 \
                    and services['configurations'] \
                    and 'admin-properties' in services['configurations'] and 'policymgr_external_url' in \
                    services['configurations']['admin-properties']['properties'] \
                    and services['configurations']['admin-properties']['properties']['policymgr_external_url'] \
                    and services['configurations']['admin-properties']['properties']['policymgr_external_url'].strip():

                # in case of HA deployment keep the policymgr_external_url specified in the config
                policymgr_external_url = services['configurations'][
                    'admin-properties']['properties']['policymgr_external_url']
            else:

                ranger_admin_host = ranger_admin_hosts[0]
                policymgr_external_url = "%s://%s:%s" % (
                    protocol, ranger_admin_host, port)

            putRangerAdminProperty('policymgr_external_url',
                                   policymgr_external_url)

    def recommendRangerConfigurationsFromHDP22(self, configurations,
                                               clusterData, services, hosts):
        putRangerEnvProperty = self.putProperty(configurations, "ranger-env")
        cluster_env = self.getServicesSiteProperties(services, "cluster-env")
        security_enabled = cluster_env is not None and "security_enabled" in cluster_env and \
                           cluster_env["security_enabled"].lower() == "true"
        if "ranger-env" in configurations and not security_enabled:
            putRangerEnvProperty("ranger-storm-plugin-enabled", "No")

    def getDBConnectionHostPort(self, db_type, db_host):
        connection_string = ""
        if db_type is None or db_type == "":
            return connection_string
        else:
            colon_count = db_host.count(':')
            if colon_count == 0:
                if DB_TYPE_DEFAULT_PORT_MAP.has_key(db_type):
                    connection_string = db_host + ":" + DB_TYPE_DEFAULT_PORT_MAP[
                        db_type]
                else:
                    connection_string = db_host
            elif colon_count == 1:
                connection_string = db_host
            elif colon_count == 2:
                connection_string = db_host

        return connection_string

    def getOracleDBConnectionHostPort(self, db_type, db_host, rangerDbName):
        connection_string = self.getDBConnectionHostPort(db_type, db_host)
        colon_count = db_host.count(':')
        if colon_count == 1 and '/' in db_host:
            connection_string = "//" + connection_string
        elif colon_count == 0 or colon_count == 1:
            connection_string = "//" + connection_string + "/" + rangerDbName if rangerDbName else "//" + connection_string

        return connection_string

    def recommendRangerUrlConfigurations(self, configurations, services,
                                         requiredServices):
        servicesList = [
            service["StackServices"]["service_name"]
            for service in services["services"]
        ]

        policymgr_external_url = ""
        if 'admin-properties' in services[
            'configurations'] and 'policymgr_external_url' in services[
            'configurations']['admin-properties']['properties']:
            if 'admin-properties' in configurations and 'policymgr_external_url' in configurations[
                'admin-properties']['properties']:
                policymgr_external_url = configurations['admin-properties'][
                    'properties']['policymgr_external_url']
            else:
                policymgr_external_url = services['configurations'][
                    'admin-properties']['properties']['policymgr_external_url']

        for index in range(len(requiredServices)):
            if requiredServices[index]['service_name'] in servicesList:
                component_config_type = requiredServices[index]['config_type']
                component_name = requiredServices[index]['service_name']
                component_config_property = 'ranger.plugin.{0}.policy.rest.url'.format(
                    component_name.lower())
                if requiredServices[index]['service_name'] == 'RANGER_KMS':
                    component_config_property = 'ranger.plugin.kms.policy.rest.url'
                putRangerSecurityProperty = self.putProperty(
                    configurations, component_config_type, services)
                if component_config_type in services[
                    "configurations"] and component_config_property in services[
                    "configurations"][component_config_type][
                    "properties"]:
                    putRangerSecurityProperty(component_config_property,
                                              policymgr_external_url)

    def recommendRangerConfigurationsFromHDP23(self, configurations,
                                               clusterData, services, hosts):
        servicesList = [
            service["StackServices"]["service_name"]
            for service in services["services"]
        ]
        putRangerAdminProperty = self.putProperty(
            configurations, "ranger-admin-site", services)
        putRangerEnvProperty = self.putProperty(configurations, "ranger-env",
                                                services)
        putRangerUgsyncSite = self.putProperty(configurations,
                                               "ranger-ugsync-site", services)

        if 'admin-properties' in services['configurations'] and (
                'DB_FLAVOR' in services['configurations']['admin-properties']['properties']) \
                and ('db_host' in services['configurations']['admin-properties']['properties']) and (
                'db_name' in services['configurations']['admin-properties']['properties']):

            rangerDbFlavor = services['configurations']["admin-properties"][
                "properties"]["DB_FLAVOR"]
            rangerDbHost = services['configurations']["admin-properties"][
                "properties"]["db_host"]
            rangerDbName = services['configurations']["admin-properties"][
                "properties"]["db_name"]
            ranger_db_url_dict = {
                'MYSQL': {
                    'ranger.jpa.jdbc.driver':
                        'com.mysql.jdbc.Driver',
                    'ranger.jpa.jdbc.url':
                        'jdbc:mysql://' + self.getDBConnectionHostPort(
                            rangerDbFlavor, rangerDbHost) + '/' + rangerDbName
                },
                'ORACLE': {
                    'ranger.jpa.jdbc.driver':
                        'oracle.jdbc.driver.OracleDriver',
                    'ranger.jpa.jdbc.url':
                        'jdbc:oracle:thin:@' + self.getOracleDBConnectionHostPort(
                            rangerDbFlavor, rangerDbHost, rangerDbName)
                },
                'POSTGRES': {
                    'ranger.jpa.jdbc.driver':
                        'org.postgresql.Driver',
                    'ranger.jpa.jdbc.url':
                        'jdbc:postgresql://' + self.getDBConnectionHostPort(
                            rangerDbFlavor, rangerDbHost) + '/' + rangerDbName
                },
                'MSSQL': {
                    'ranger.jpa.jdbc.driver':
                        'com.microsoft.sqlserver.jdbc.SQLServerDriver',
                    'ranger.jpa.jdbc.url':
                        'jdbc:sqlserver://' + self.getDBConnectionHostPort(
                            rangerDbFlavor, rangerDbHost) + ';databaseName=' +
                        rangerDbName
                },
                'SQLA': {
                    'ranger.jpa.jdbc.driver':
                        'sap.jdbc4.sqlanywhere.IDriver',
                    'ranger.jpa.jdbc.url':
                        'jdbc:sqlanywhere:host=' + self.getDBConnectionHostPort(
                            rangerDbFlavor, rangerDbHost) + ';database=' +
                        rangerDbName
                }
            }
            rangerDbProperties = ranger_db_url_dict.get(
                rangerDbFlavor, ranger_db_url_dict['MYSQL'])
            for key in rangerDbProperties:
                putRangerAdminProperty(key, rangerDbProperties.get(key))

            if 'admin-properties' in services['configurations'] and (
                    'DB_FLAVOR' in services['configurations']['admin-properties']['properties']) \
                    and ('db_host' in services['configurations']['admin-properties']['properties']):

                rangerDbFlavor = services['configurations'][
                    "admin-properties"]["properties"]["DB_FLAVOR"]
                rangerDbHost = services['configurations']["admin-properties"][
                    "properties"]["db_host"]
                ranger_db_privelege_url_dict = {
                    'MYSQL': {
                        'ranger_privelege_user_jdbc_url':
                            'jdbc:mysql://' + self.getDBConnectionHostPort(
                                rangerDbFlavor, rangerDbHost)
                    },
                    'ORACLE': {
                        'ranger_privelege_user_jdbc_url':
                            'jdbc:oracle:thin:@' +
                            self.getOracleDBConnectionHostPort(
                                rangerDbFlavor, rangerDbHost, None)
                    },
                    'POSTGRES': {
                        'ranger_privelege_user_jdbc_url':
                            'jdbc:postgresql://' + self.getDBConnectionHostPort(
                                rangerDbFlavor, rangerDbHost) + '/postgres'
                    },
                    'MSSQL': {
                        'ranger_privelege_user_jdbc_url':
                            'jdbc:sqlserver://' + self.getDBConnectionHostPort(
                                rangerDbFlavor, rangerDbHost) + ';'
                    },
                    'SQLA': {
                        'ranger_privelege_user_jdbc_url':
                            'jdbc:sqlanywhere:host=' +
                            self.getDBConnectionHostPort(rangerDbFlavor,
                                                         rangerDbHost) + ';'
                    }
                }
                rangerPrivelegeDbProperties = ranger_db_privelege_url_dict.get(
                    rangerDbFlavor, ranger_db_privelege_url_dict['MYSQL'])
                for key in rangerPrivelegeDbProperties:
                    putRangerEnvProperty(key,
                                         rangerPrivelegeDbProperties.get(key))

        # Recommend ldap settings based on ambari.properties configuration
        if 'ambari-server-properties' in services and \
                'ambari.ldap.isConfigured' in services['ambari-server-properties'] and \
                services['ambari-server-properties']['ambari.ldap.isConfigured'].lower() == "true":
            serverProperties = services['ambari-server-properties']
            if 'authentication.ldap.baseDn' in serverProperties:
                putRangerUgsyncSite(
                    'ranger.usersync.ldap.searchBase',
                    serverProperties['authentication.ldap.baseDn'])
            if 'authentication.ldap.groupMembershipAttr' in serverProperties:
                putRangerUgsyncSite(
                    'ranger.usersync.group.memberattributename',
                    serverProperties['authentication.ldap.groupMembershipAttr']
                )
            if 'authentication.ldap.groupNamingAttr' in serverProperties:
                putRangerUgsyncSite(
                    'ranger.usersync.group.nameattribute',
                    serverProperties['authentication.ldap.groupNamingAttr'])
            if 'authentication.ldap.groupObjectClass' in serverProperties:
                putRangerUgsyncSite(
                    'ranger.usersync.group.objectclass',
                    serverProperties['authentication.ldap.groupObjectClass'])
            if 'authentication.ldap.managerDn' in serverProperties:
                putRangerUgsyncSite(
                    'ranger.usersync.ldap.binddn',
                    serverProperties['authentication.ldap.managerDn'])
            if 'authentication.ldap.primaryUrl' in serverProperties:
                ldap_protocol = 'ldap://'
                if 'authentication.ldap.useSSL' in serverProperties and serverProperties[
                    'authentication.ldap.useSSL'] == 'true':
                    ldap_protocol = 'ldaps://'
                ldapUrl = ldap_protocol + serverProperties[
                    'authentication.ldap.primaryUrl'] if serverProperties[
                    'authentication.ldap.primaryUrl'] else serverProperties[
                    'authentication.ldap.primaryUrl']
                putRangerUgsyncSite('ranger.usersync.ldap.url', ldapUrl)
            if 'authentication.ldap.userObjectClass' in serverProperties:
                putRangerUgsyncSite(
                    'ranger.usersync.ldap.user.objectclass',
                    serverProperties['authentication.ldap.userObjectClass'])
            if 'authentication.ldap.usernameAttribute' in serverProperties:
                putRangerUgsyncSite(
                    'ranger.usersync.ldap.user.nameattribute',
                    serverProperties['authentication.ldap.usernameAttribute'])

        # Recommend Ranger Authentication method
        authMap = {
            'org.apache.ranger.unixusersync.process.UnixUserGroupBuilder':
                'UNIX',
            'org.apache.ranger.ldapusersync.process.LdapUserGroupBuilder':
                'LDAP'
        }

        if 'ranger-ugsync-site' in services[
            'configurations'] and 'ranger.usersync.source.impl.class' in services[
            'configurations']["ranger-ugsync-site"]["properties"]:
            rangerUserSyncClass = services['configurations'][
                "ranger-ugsync-site"]["properties"][
                "ranger.usersync.source.impl.class"]
            if rangerUserSyncClass in authMap:
                rangerSqlConnectorProperty = authMap.get(rangerUserSyncClass)
                putRangerAdminProperty('ranger.authentication.method',
                                       rangerSqlConnectorProperty)

        if 'ranger-env' in services[
            'configurations'] and 'is_solrCloud_enabled' in services[
            'configurations']["ranger-env"]["properties"]:
            isSolrCloudEnabled = services['configurations']["ranger-env"][
                                     "properties"]["is_solrCloud_enabled"] == "true"
        else:
            isSolrCloudEnabled = False

        if isSolrCloudEnabled:
            zookeeper_host_port = self.getZKHostPortString(services)
            ranger_audit_zk_port = ''
            if zookeeper_host_port:
                ranger_audit_zk_port = '{0}/{1}'.format(
                    zookeeper_host_port, 'infra-solr')
                putRangerAdminProperty('ranger.audit.solr.zookeepers',
                                       ranger_audit_zk_port)
        else:
            putRangerAdminProperty('ranger.audit.solr.zookeepers', 'NONE')

        # Recommend ranger.audit.solr.zookeepers and xasecure.audit.destination.hdfs.dir
        include_hdfs = "HDFS" in servicesList
        if include_hdfs:
            if 'core-site' in services['configurations'] and (
                    'fs.defaultFS' in services['configurations']['core-site']
            ['properties']):
                default_fs = services['configurations']['core-site'][
                    'properties']['fs.defaultFS']
                putRangerEnvProperty(
                    'xasecure.audit.destination.hdfs.dir',
                    '{0}/{1}/{2}'.format(default_fs, 'ranger', 'audit'))

        # Recommend Ranger supported service's audit properties
        ranger_services = [{
            'service_name': 'HDFS',
            'audit_file': 'ranger-hdfs-audit'
        }, {
            'service_name': 'YARN',
            'audit_file': 'ranger-yarn-audit'
        }, {
            'service_name': 'HBASE',
            'audit_file': 'ranger-hbase-audit'
        }, {
            'service_name': 'HIVE',
            'audit_file': 'ranger-hive-audit'
        }, {
            'service_name': 'KNOX',
            'audit_file': 'ranger-knox-audit'
        }, {
            'service_name': 'KAFKA',
            'audit_file': 'ranger-kafka-audit'
        }, {
            'service_name': 'STORM',
            'audit_file': 'ranger-storm-audit'
        }]

        for item in range(len(ranger_services)):
            if ranger_services[item]['service_name'] in servicesList:
                component_audit_file = ranger_services[item]['audit_file']
                if component_audit_file in services["configurations"]:
                    ranger_audit_dict = [
                        {
                            'filename': 'ranger-env',
                            'configname': 'xasecure.audit.destination.db',
                            'target_configname':
                                'xasecure.audit.destination.db'
                        },
                        {
                            'filename': 'ranger-env',
                            'configname': 'xasecure.audit.destination.hdfs',
                            'target_configname':
                                'xasecure.audit.destination.hdfs'
                        },
                        {
                            'filename':
                                'ranger-env',
                            'configname':
                                'xasecure.audit.destination.hdfs.dir',
                            'target_configname':
                                'xasecure.audit.destination.hdfs.dir'
                        },
                        {
                            'filename': 'ranger-env',
                            'configname': 'xasecure.audit.destination.solr',
                            'target_configname':
                                'xasecure.audit.destination.solr'
                        },
                        {
                            'filename':
                                'ranger-admin-site',
                            'configname':
                                'ranger.audit.solr.urls',
                            'target_configname':
                                'xasecure.audit.destination.solr.urls'
                        },
                        {
                            'filename':
                                'ranger-admin-site',
                            'configname':
                                'ranger.audit.solr.zookeepers',
                            'target_configname':
                                'xasecure.audit.destination.solr.zookeepers'
                        }
                    ]
                    putRangerAuditProperty = self.putProperty(
                        configurations, component_audit_file, services)

                    for item in ranger_audit_dict:
                        if item['filename'] in services[
                            "configurations"] and item[
                            'configname'] in services["configurations"][
                            item['filename']]["properties"]:
                            if item['filename'] in configurations and item[
                                'configname'] in configurations[
                                item['filename']]["properties"]:
                                rangerAuditProperty = configurations[
                                    item['filename']]["properties"][
                                    item['configname']]
                            else:
                                rangerAuditProperty = services[
                                    "configurations"][item['filename']][
                                    "properties"][item['configname']]
                            putRangerAuditProperty(item['target_configname'],
                                                   rangerAuditProperty)

        audit_solr_flag = 'false'
        audit_db_flag = 'false'
        ranger_audit_source_type = 'solr'
        if 'ranger-env' in services[
            'configurations'] and 'xasecure.audit.destination.solr' in services[
            'configurations']["ranger-env"]["properties"]:
            audit_solr_flag = services['configurations']["ranger-env"][
                "properties"]['xasecure.audit.destination.solr']
        if 'ranger-env' in services[
            'configurations'] and 'xasecure.audit.destination.db' in services[
            'configurations']["ranger-env"]["properties"]:
            audit_db_flag = services['configurations']["ranger-env"][
                "properties"]['xasecure.audit.destination.db']

        if audit_db_flag == 'true' and audit_solr_flag == 'false':
            ranger_audit_source_type = 'db'
        putRangerAdminProperty('ranger.audit.source.type',
                               ranger_audit_source_type)

        knox_host = 'localhost'
        knox_port = '8443'
        if 'KNOX' in servicesList:
            knox_hosts = self.getComponentHostNames(services, "KNOX",
                                                    "KNOX_GATEWAY")
            if len(knox_hosts) > 0:
                knox_hosts.sort()
                knox_host = knox_hosts[0]
            if 'gateway-site' in services[
                'configurations'] and 'gateway.port' in services[
                'configurations']["gateway-site"]["properties"]:
                knox_port = services['configurations']["gateway-site"][
                    "properties"]['gateway.port']
            putRangerAdminProperty(
                'ranger.sso.providerurl',
                'https://{0}:{1}/gateway/knoxsso/api/v1/websso'.format(
                    knox_host, knox_port))

        required_services = [{
            'service_name': 'HDFS',
            'config_type': 'ranger-hdfs-security'
        }, {
            'service_name': 'YARN',
            'config_type': 'ranger-yarn-security'
        }, {
            'service_name': 'HBASE',
            'config_type': 'ranger-hbase-security'
        }, {
            'service_name': 'HIVE',
            'config_type': 'ranger-hive-security'
        }, {
            'service_name': 'KNOX',
            'config_type': 'ranger-knox-security'
        }, {
            'service_name': 'KAFKA',
            'config_type': 'ranger-kafka-security'
        }, {
            'service_name': 'RANGER_KMS',
            'config_type': 'ranger-kms-security'
        }, {
            'service_name': 'STORM',
            'config_type': 'ranger-storm-security'
        }]

        # recommendation for ranger url for ranger-supported plugins
        self.recommendRangerUrlConfigurations(configurations, services,
                                              required_services)

    def recommendRangerConfigurationsFromHDP25(self, configurations,
                                               clusterData, services, hosts):
        servicesList = [
            service["StackServices"]["service_name"]
            for service in services["services"]
        ]
        has_ranger_tagsync = False

        putTagsyncAppProperty = self.putProperty(
            configurations, "tagsync-application-properties", services)
        putTagsyncSiteProperty = self.putProperty(
            configurations, "ranger-tagsync-site", services)
        putRangerAdminProperty = self.putProperty(
            configurations, "ranger-admin-site", services)
        putRangerEnvProperty = self.putProperty(configurations, "ranger-env",
                                                services)

        application_properties = self.getServicesSiteProperties(
            services, "application-properties")

        ranger_tagsync_host = self.getHostsForComponent(
            services, "RANGER", "RANGER_TAGSYNC")
        has_ranger_tagsync = len(ranger_tagsync_host) > 0

        if 'ATLAS' in servicesList and has_ranger_tagsync:
            atlas_hosts = self.getHostNamesWithComponent(
                "ATLAS", "ATLAS_SERVER", services)
            atlas_host = 'localhost' if len(
                atlas_hosts) == 0 else atlas_hosts[0]
            protocol = 'http'
            atlas_port = '21000'

            if application_properties and 'atlas.enableTLS' in application_properties and application_properties[
                'atlas.enableTLS'].lower() == 'true':
                protocol = 'https'
                if 'atlas.server.https.port' in application_properties:
                    atlas_port = application_properties[
                        'atlas.server.https.port']
            else:
                protocol = 'http'
                if application_properties and 'atlas.server.http.port' in application_properties:
                    atlas_port = application_properties[
                        'atlas.server.http.port']

            atlas_rest_endpoint = '{0}://{1}:{2}'.format(
                protocol, atlas_host, atlas_port)

            putTagsyncSiteProperty('ranger.tagsync.source.atlas', 'true')
            putTagsyncSiteProperty('ranger.tagsync.source.atlasrest.endpoint',
                                   atlas_rest_endpoint)

        zookeeper_host_port = self.getZKHostPortString(services)
        if zookeeper_host_port and has_ranger_tagsync:
            putTagsyncAppProperty('atlas.kafka.zookeeper.connect',
                                  zookeeper_host_port)

        if 'CONFLUENT' in servicesList and has_ranger_tagsync:
            kafka_hosts = self.getHostNamesWithComponent(
                "CONFLUENT", "KAFKA", services)
            from random import shuffle
            shuffle(kafka_hosts)
            kafka_port = '6667'
            kafka_host_port = []
            for i in range(len(kafka_hosts)):
                kafka_host_port.append(kafka_hosts[i] + ':' + kafka_port)

            final_kafka_host = ",".join(kafka_host_port)
            putTagsyncAppProperty('atlas.kafka.bootstrap.servers',
                                  final_kafka_host)

        is_solr_cloud_enabled = False
        if 'ranger-env' in services[
            'configurations'] and 'is_solrCloud_enabled' in services[
            'configurations']['ranger-env']['properties']:
            is_solr_cloud_enabled = services['configurations']['ranger-env'][
                                        'properties']['is_solrCloud_enabled'] == 'true'

        is_external_solr_cloud_enabled = False
        if 'ranger-env' in services[
            'configurations'] and 'is_external_solrCloud_enabled' in services[
            'configurations']['ranger-env']['properties']:
            is_external_solr_cloud_enabled = services['configurations'][
                                                 'ranger-env']['properties'][
                                                 'is_external_solrCloud_enabled'] == 'true'

        ranger_audit_zk_port = ''

        if 'AMBARI_INFRA_SOLR' in servicesList and zookeeper_host_port and is_solr_cloud_enabled and not is_external_solr_cloud_enabled:
            zookeeper_host_port = zookeeper_host_port.split(',')
            zookeeper_host_port.sort()
            zookeeper_host_port = ",".join(zookeeper_host_port)
            infra_solr_znode = '/infra-solr'

            if 'infra-solr-env' in services['configurations'] and \
                    ('infra_solr_znode' in services['configurations']['infra-solr-env']['properties']):
                infra_solr_znode = services['configurations'][
                    'infra-solr-env']['properties']['infra_solr_znode']
                ranger_audit_zk_port = '{0}{1}'.format(zookeeper_host_port,
                                                       infra_solr_znode)
            putRangerAdminProperty('ranger.audit.solr.zookeepers',
                                   ranger_audit_zk_port)
        elif zookeeper_host_port and is_solr_cloud_enabled and is_external_solr_cloud_enabled:
            ranger_audit_zk_port = '{0}/{1}'.format(zookeeper_host_port,
                                                    'infra-solr')
            putRangerAdminProperty('ranger.audit.solr.zookeepers',
                                   ranger_audit_zk_port)
        else:
            putRangerAdminProperty('ranger.audit.solr.zookeepers', 'NONE')

        ranger_services = [{
            'service_name': 'HDFS',
            'audit_file': 'ranger-hdfs-audit'
        }, {
            'service_name': 'YARN',
            'audit_file': 'ranger-yarn-audit'
        }, {
            'service_name': 'HBASE',
            'audit_file': 'ranger-hbase-audit'
        }, {
            'service_name': 'HIVE',
            'audit_file': 'ranger-hive-audit'
        }, {
            'service_name': 'KNOX',
            'audit_file': 'ranger-knox-audit'
        }, {
            'service_name': 'KAFKA',
            'audit_file': 'ranger-kafka-audit'
        }, {
            'service_name': 'STORM',
            'audit_file': 'ranger-storm-audit'
        }, {
            'service_name': 'RANGER_KMS',
            'audit_file': 'ranger-kms-audit'
        }, {
            'service_name': 'ATLAS',
            'audit_file': 'ranger-atlas-audit'
        }]

        for item in range(len(ranger_services)):
            if ranger_services[item]['service_name'] in servicesList:
                component_audit_file = ranger_services[item]['audit_file']
                if component_audit_file in services["configurations"]:
                    ranger_audit_dict = [
                        {
                            'filename':
                                'ranger-admin-site',
                            'configname':
                                'ranger.audit.solr.urls',
                            'target_configname':
                                'xasecure.audit.destination.solr.urls'
                        },
                        {
                            'filename':
                                'ranger-admin-site',
                            'configname':
                                'ranger.audit.solr.zookeepers',
                            'target_configname':
                                'xasecure.audit.destination.solr.zookeepers'
                        }
                    ]
                    putRangerAuditProperty = self.putProperty(
                        configurations, component_audit_file, services)

                    for item in ranger_audit_dict:
                        if item['filename'] in services[
                            "configurations"] and item[
                            'configname'] in services["configurations"][
                            item['filename']]["properties"]:
                            if item['filename'] in configurations and item[
                                'configname'] in configurations[
                                item['filename']]["properties"]:
                                rangerAuditProperty = configurations[
                                    item['filename']]["properties"][
                                    item['configname']]
                            else:
                                rangerAuditProperty = services[
                                    "configurations"][item['filename']][
                                    "properties"][item['configname']]
                            putRangerAuditProperty(item['target_configname'],
                                                   rangerAuditProperty)

        if "HDFS" in servicesList:
            hdfs_user = None
            if "hadoop-env" in services[
                "configurations"] and "hdfs_user" in services[
                "configurations"]["hadoop-env"]["properties"]:
                hdfs_user = services["configurations"]["hadoop-env"][
                    "properties"]["hdfs_user"]
                putRangerAdminProperty('ranger.kms.service.user.hdfs',
                                       hdfs_user)

        if "HIVE" in servicesList:
            hive_user = None
            if "hive-env" in services[
                "configurations"] and "hive_user" in services[
                "configurations"]["hive-env"]["properties"]:
                hive_user = services["configurations"]["hive-env"][
                    "properties"]["hive_user"]
                putRangerAdminProperty('ranger.kms.service.user.hive',
                                       hive_user)

        ranger_plugins_serviceuser = [{
            'service_name':
                'HDFS',
            'file_name':
                'hadoop-env',
            'config_name':
                'hdfs_user',
            'target_configname':
                'ranger.plugins.hdfs.serviceuser'
        },
            {
                'service_name':
                    'HIVE',
                'file_name':
                    'hive-env',
                'config_name':
                    'hive_user',
                'target_configname':
                    'ranger.plugins.hive.serviceuser'
            },
            {
                'service_name':
                    'YARN',
                'file_name':
                    'yarn-env',
                'config_name':
                    'yarn_user',
                'target_configname':
                    'ranger.plugins.yarn.serviceuser'
            },
            {
                'service_name':
                    'HBASE',
                'file_name':
                    'hbase-env',
                'config_name':
                    'hbase_user',
                'target_configname':
                    'ranger.plugins.hbase.serviceuser'
            },
            {
                'service_name':
                    'KNOX',
                'file_name':
                    'knox-env',
                'config_name':
                    'knox_user',
                'target_configname':
                    'ranger.plugins.knox.serviceuser'
            },
            {
                'service_name':
                    'STORM',
                'file_name':
                    'storm-env',
                'config_name':
                    'storm_user',
                'target_configname':
                    'ranger.plugins.storm.serviceuser'
            },
            {
                'service_name':
                    'KAFKA',
                'file_name':
                    'kafka-env',
                'config_name':
                    'kafka_user',
                'target_configname':
                    'ranger.plugins.kafka.serviceuser'
            },
            {
                'service_name':
                    'RANGER_KMS',
                'file_name':
                    'kms-env',
                'config_name':
                    'kms_user',
                'target_configname':
                    'ranger.plugins.kms.serviceuser'
            },
            {
                'service_name':
                    'ATLAS',
                'file_name':
                    'atlas-env',
                'config_name':
                    'metadata_user',
                'target_configname':
                    'ranger.plugins.atlas.serviceuser'
            }]

        for item in range(len(ranger_plugins_serviceuser)):
            if ranger_plugins_serviceuser[item][
                'service_name'] in servicesList:
                file_name = ranger_plugins_serviceuser[item]['file_name']
                config_name = ranger_plugins_serviceuser[item]['config_name']
                target_configname = ranger_plugins_serviceuser[item][
                    'target_configname']
                if file_name in services[
                    "configurations"] and config_name in services[
                    "configurations"][file_name]["properties"]:
                    service_user = services["configurations"][file_name][
                        "properties"][config_name]
                    putRangerAdminProperty(target_configname, service_user)

        if "ATLAS" in servicesList:
            if "ranger-env" in services["configurations"]:
                putAtlasRangerAuditProperty = self.putProperty(
                    configurations, 'ranger-atlas-audit', services)
                xasecure_audit_destination_hdfs = ''
                xasecure_audit_destination_hdfs_dir = ''
                xasecure_audit_destination_solr = ''
                if 'xasecure.audit.destination.hdfs' in configurations[
                    'ranger-env']['properties']:
                    xasecure_audit_destination_hdfs = configurations[
                        'ranger-env']['properties'][
                        'xasecure.audit.destination.hdfs']
                else:
                    xasecure_audit_destination_hdfs = services[
                        'configurations']['ranger-env']['properties'][
                        'xasecure.audit.destination.hdfs']

                if 'core-site' in services['configurations'] and (
                        'fs.defaultFS' in services['configurations']
                ['core-site']['properties']):
                    xasecure_audit_destination_hdfs_dir = '{0}/{1}/{2}'.format(
                        services['configurations']['core-site']['properties']
                        ['fs.defaultFS'], 'ranger', 'audit')

                if 'xasecure.audit.destination.solr' in configurations[
                    'ranger-env']['properties']:
                    xasecure_audit_destination_solr = configurations[
                        'ranger-env']['properties'][
                        'xasecure.audit.destination.solr']
                else:
                    xasecure_audit_destination_solr = services[
                        'configurations']['ranger-env']['properties'][
                        'xasecure.audit.destination.solr']

                putAtlasRangerAuditProperty('xasecure.audit.destination.hdfs',
                                            xasecure_audit_destination_hdfs)
                putAtlasRangerAuditProperty(
                    'xasecure.audit.destination.hdfs.dir',
                    xasecure_audit_destination_hdfs_dir)
                putAtlasRangerAuditProperty('xasecure.audit.destination.solr',
                                            xasecure_audit_destination_solr)
        required_services = [{
            'service_name': 'ATLAS',
            'config_type': 'ranger-atlas-security'
        }]

        # recommendation for ranger url for ranger-supported plugins
        self.recommendRangerUrlConfigurations(configurations, services,
                                              required_services)

    def recommendRangerConfigurationsFromHDP26(self, configurations,
                                               clusterData, services, hosts):

        putRangerUgsyncSite = self.putProperty(configurations,
                                               'ranger-ugsync-site', services)

        delta_sync_enabled = False
        if 'ranger-ugsync-site' in services[
            'configurations'] and 'ranger.usersync.ldap.deltasync' in services[
            'configurations']['ranger-ugsync-site']['properties']:
            delta_sync_enabled = services['configurations'][
                                     'ranger-ugsync-site']['properties'][
                                     'ranger.usersync.ldap.deltasync'] == "true"

        if delta_sync_enabled:
            putRangerUgsyncSite("ranger.usersync.group.searchenabled", "true")
        else:
            putRangerUgsyncSite("ranger.usersync.group.searchenabled", "false")

    def recommendConfigurationsForSSO(self, configurations, clusterData,
                                      services, hosts):
        ambari_configuration = self.get_ambari_configuration(services)
        ambari_sso_details = ambari_configuration.get_ambari_sso_details(
        ) if ambari_configuration else None

        if ambari_sso_details and ambari_sso_details.is_managing_services():
            putRangerAdminSiteProperty = self.putProperty(
                configurations, "ranger-admin-site", services)

            # If SSO should be enabled for this service, continue
            if ambari_sso_details.should_enable_sso('RANGER'):
                putRangerAdminSiteProperty('ranger.sso.enabled', "true")
                putRangerAdminSiteProperty(
                    'ranger.sso.providerurl',
                    ambari_sso_details.get_sso_provider_url())
                putRangerAdminSiteProperty(
                    'ranger.sso.publicKey',
                    ambari_sso_details.get_sso_provider_certificate(
                        False, True))
                putRangerAdminSiteProperty('ranger.sso.browser.useragent',
                                           'Mozilla,chrome')

            # If SSO should be disabled for this service
            elif ambari_sso_details.should_disable_sso('RANGER'):
                putRangerAdminSiteProperty('ranger.sso.enabled', "false")

    def recommendConfigurationsForHDP30(self, configurations, clusterData,
                                        services, hosts):
        putRangerAdminProperty = self.putProperty(
            configurations, 'ranger-admin-site', services)

        enable_usersync_ldap_starttls = False
        if 'ranger-ugsync-site' in services[
            'configurations'] and 'ranger.usersync.ldap.starttls' in services[
            'configurations']['ranger-ugsync-site']['properties']:
            enable_usersync_ldap_starttls = services['configurations'][
                                                'ranger-ugsync-site']['properties'][
                                                'ranger.usersync.ldap.starttls'] == "true"

        if enable_usersync_ldap_starttls:
            putRangerAdminProperty("ranger.ldap.starttls", "true")
        else:
            putRangerAdminProperty("ranger.ldap.starttls", "false")

    def recommendRangerConfigurationsFromHDP31(self, configurations,
                                               clusterData, services, hosts):

        putRangerAdminProperty = self.putProperty(
            configurations, "ranger-admin-site", services)
        putRangerAdminAttribute = self.putPropertyAttribute(
            configurations, "ranger-admin-site")
        servicesList = [
            service["StackServices"]["service_name"]
            for service in services["services"]
        ]

        if 'forced-configurations' not in services:
            services["forced-configurations"] = []

        if "KNOX" in servicesList:
            knox_host = self.getHostWithComponent("KNOX", "KNOX_GATEWAY",
                                                  services, hosts)
            knox_host_ip = knox_host['Hosts']['ip']

            if 'knox-env' in services[
                'configurations'] and 'knox_user' in services[
                'configurations']['knox-env']['properties']:
                knox_user = services['configurations']['knox-env'][
                    'properties']['knox_user']
                knox_old_user = self.getOldValue(services, "knox-env",
                                                 "knox_user")

                putRangerAdminProperty(
                    'ranger.proxyuser.{0}.users'.format(knox_user), '*')
                putRangerAdminProperty(
                    'ranger.proxyuser.{0}.hosts'.format(knox_user), '*')
                putRangerAdminProperty(
                    'ranger.proxyuser.{0}.groups'.format(knox_user), '*')
                putRangerAdminProperty(
                    'ranger.proxyuser.{0}.ip'.format(knox_user), knox_host_ip)

                if knox_old_user is not None and knox_user != knox_old_user:
                    putRangerAdminAttribute(
                        'ranger.proxyuser.{0}.users'.format(knox_old_user),
                        'delete', 'true')
                    services['forced-configurations'].append({
                        'type':
                            'ranger-admin-site',
                        'name':
                            'ranger.proxyuser.{0}.users'.format(knox_old_user)
                    })
                    services['forced-configurations'].append({
                        'type':
                            'ranger-admin-site',
                        'name':
                            'ranger.proxyuser.{0}.users'.format(knox_user)
                    })

                    putRangerAdminAttribute(
                        'ranger.proxyuser.{0}.hosts'.format(knox_old_user),
                        'delete', 'true')
                    services['forced-configurations'].append({
                        'type':
                            'ranger-admin-site',
                        'name':
                            'ranger.proxyuser.{0}.hosts'.format(knox_old_user)
                    })
                    services['forced-configurations'].append({
                        'type':
                            'ranger-admin-site',
                        'name':
                            'ranger.proxyuser.{0}.hosts'.format(knox_user)
                    })

                    putRangerAdminAttribute(
                        'ranger.proxyuser.{0}.groups'.format(knox_old_user),
                        'delete', 'true')
                    services['forced-configurations'].append({
                        'type':
                            'ranger-admin-site',
                        'name':
                            'ranger.proxyuser.{0}.groups'.format(knox_old_user)
                    })
                    services['forced-configurations'].append({
                        'type':
                            'ranger-admin-site',
                        'name':
                            'ranger.proxyuser.{0}.groups'.format(knox_user)
                    })

                    putRangerAdminAttribute(
                        'ranger.proxyuser.{0}.ip'.format(knox_old_user),
                        'delete', 'true')
                    services['forced-configurations'].append({
                        'type':
                            'ranger-admin-site',
                        'name':
                            'ranger.proxyuser.{0}.ip'.format(knox_old_user)
                    })
                    services['forced-configurations'].append({
                        'type':
                            'ranger-admin-site',
                        'name':
                            'ranger.proxyuser.{0}.ip'.format(knox_user)
                    })


class RangerValidator(service_advisor.ServiceAdvisor):
    """
  Ranger Validator checks the correctness of properties whenever the service is first added or the user attempts to
  change configs via the UI.
  """

    def __init__(self, *args, **kwargs):
        self.as_super = super(RangerValidator, self)
        self.as_super.__init__(*args, **kwargs)

        self.validators = [
            ("ranger-env", self.validateRangerConfigurationsEnvFromHDP22),
            ("admin-properties",
             self.validateRangerAdminConfigurationsFromHDP23),
            ("ranger-env", self.validateRangerConfigurationsEnvFromHDP23),
            ("ranger-tagsync-site",
             self.validateRangerTagsyncConfigurationsFromHDP25),
            ("ranger-ugsync-site",
             self.validateRangerUsersyncConfigurationsFromHDP26),
            ("ranger-env", self.validateRangerPasswordConfigurations)
        ]

    def validateRangerConfigurationsEnvFromHDP22(
            self, properties, recommendedDefaults, configurations, services,
            hosts):
        ranger_env_properties = properties
        validationItems = []
        servicesList = [
            service["StackServices"]["service_name"]
            for service in services["services"]
        ]
        if "ranger-storm-plugin-enabled" in ranger_env_properties and ranger_env_properties[
            'ranger-storm-plugin-enabled'].lower(
        ) == 'yes' and not 'KERBEROS' in servicesList:
            validationItems.append({
                "config-name":
                    "ranger-storm-plugin-enabled",
                "item":
                    self.getWarnItem(
                        "Ranger Storm plugin should not be enabled in non-kerberos environment."
                    )
            })
        return self.toConfigurationValidationProblems(validationItems,
                                                      "ranger-env")

    def validateRangerAdminConfigurationsFromHDP23(
            self, properties, recommendedDefaults, configurations, services,
            hosts):
        ranger_site = properties
        validationItems = []
        servicesList = [
            service["StackServices"]["service_name"]
            for service in services["services"]
        ]
        if 'RANGER' in servicesList and 'policymgr_external_url' in ranger_site:
            policymgr_mgr_url = ranger_site['policymgr_external_url']
            if policymgr_mgr_url.endswith('/'):
                validationItems.append({
                    'config-name':
                        'policymgr_external_url',
                    'item':
                        self.getWarnItem(
                            'Ranger External URL should not contain trailing slash "/"'
                        )
                })
        return self.toConfigurationValidationProblems(validationItems,
                                                      'admin-properties')

    def validateRangerConfigurationsEnvFromHDP23(
            self, properties, recommendedDefaults, configurations, services,
            hosts):
        ranger_env_properties = properties
        validationItems = []
        security_enabled = RangerServiceAdvisor.isKerberosEnabled(
            services, configurations)

        if "ranger-kafka-plugin-enabled" in ranger_env_properties and ranger_env_properties[
            "ranger-kafka-plugin-enabled"].lower(
        ) == 'yes' and not security_enabled:
            validationItems.append({
                "config-name":
                    "ranger-kafka-plugin-enabled",
                "item":
                    self.getWarnItem(
                        "Ranger Kafka plugin should not be enabled in non-kerberos environment."
                    )
            })

        validationProblems = self.toConfigurationValidationProblems(
            validationItems, "ranger-env")
        return validationProblems

    def validateRangerTagsyncConfigurationsFromHDP25(
            self, properties, recommendedDefaults, configurations, services,
            hosts):
        ranger_tagsync_properties = properties
        validationItems = []
        servicesList = [
            service["StackServices"]["service_name"]
            for service in services["services"]
        ]

        has_atlas = False
        if "RANGER" in servicesList:
            has_atlas = not "ATLAS" in servicesList

            if has_atlas and 'ranger.tagsync.source.atlas' in ranger_tagsync_properties and \
                    ranger_tagsync_properties['ranger.tagsync.source.atlas'].lower() == 'true':
                validationItems.append({
                    "config-name":
                        "ranger.tagsync.source.atlas",
                    "item":
                        self.getWarnItem(
                            "Need to Install ATLAS service to set ranger.tagsync.source.atlas as true."
                        )
                })

        return self.toConfigurationValidationProblems(validationItems,
                                                      "ranger-tagsync-site")

    def validateRangerUsersyncConfigurationsFromHDP26(
            self, properties, recommendedDefaults, configurations, services,
            hosts):
        ranger_usersync_properties = properties
        validationItems = []

        delta_sync_enabled = 'ranger.usersync.ldap.deltasync' in ranger_usersync_properties \
                             and ranger_usersync_properties['ranger.usersync.ldap.deltasync'].lower() == 'true'
        group_sync_enabled = 'ranger.usersync.group.searchenabled' in ranger_usersync_properties \
                             and ranger_usersync_properties['ranger.usersync.group.searchenabled'].lower() == 'true'
        usersync_source_ldap_enabled = 'ranger.usersync.source.impl.class' in ranger_usersync_properties \
                                       and ranger_usersync_properties[
                                           'ranger.usersync.source.impl.class'] == 'org.apache.ranger.ldapusersync.process.LdapUserGroupBuilder'

        if usersync_source_ldap_enabled and delta_sync_enabled and not group_sync_enabled:
            validationItems.append({
                "config-name":
                    "ranger.usersync.group.searchenabled",
                "item":
                    self.getWarnItem(
                        "Need to set ranger.usersync.group.searchenabled as true, as ranger.usersync.ldap.deltasync is enabled"
                    )
            })

        return self.toConfigurationValidationProblems(validationItems,
                                                      "ranger-ugsync-site")

    def validateRangerPasswordConfigurations(self, properties,
                                             recommendedDefaults,
                                             configurations, services, hosts):
        ranger_env_properties = properties
        validationItems = []

        ranger_password_properties = [
            'admin_password', 'ranger_admin_password',
            'rangerusersync_user_password', 'rangertagsync_user_password',
            'keyadmin_user_password'
        ]
        for password_property in ranger_password_properties:
            if password_property in ranger_env_properties:
                password = ranger_env_properties[password_property]
                if not bool(
                        re.search(r'^(?=.*[0-9])(?=.*[a-zA-Z]).{8,}$',
                                  password)) or bool(
                    re.search('[\\\`"\']', password)):
                    validationItems.append({
                        "config-name":
                            password_property,
                        "item":
                            self.getNotApplicableItem(
                                "Password should be minimum 8 characters with minimum one alphabet and one numeric. Unsupported special characters are  \" ' \ `"
                            )
                    })

        return self.toConfigurationValidationProblems(validationItems,
                                                      "ranger-env")
